// scalaxx - Scala XML eXtensions
// (c) 2009, Normen Müller, normen.mueller@gmail.com
// $Id: Marker.scala 48 2009-11-12 11:29:56Z normen.mueller $
package scalaxx.util

import scala.xml._
import scala.xml.NodeSeq.Empty
import scala.xml.Utility.{trimProper => trim}

import scalaxx.path._

/** 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.1 */
case class Mark(before: Option[Node], self: Option[(Option[MetaData], Option[Node])], after: Option[Node])

/** 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.1 */
object Marker {
  
  def mark(doc: Node, markers: Map[LocationPath, Mark]) = new Marker(markers).mark(trim(doc), Root.childAt(1))

}

/** 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.1 */
private [util] class Marker(markers: Map[LocationPath, Mark]) {
  
  def mark(doc: NodeSeq, path: LocationPath): NodeSeq = doc.toList match {
    case hd :: tl => (hd match {
      case Elem(p,l,as,s,cs@ _*) =>
        markers get path match {
          case Some(Mark(before, self, after)) =>
            before.getOrElse(Empty) ++ (self match {
              case Some((a, e)) => e match {
                case Some(m) => Elem(p, l, as append a.getOrElse(Null), s, (m :: marks(cs, path childAt 1).toList):_*)
                case None    => Elem(p, l, as append a.getOrElse(Null), s, marks(cs, path childAt 1):_*)
              }
              case None => Elem(p, l, as, s, marks(cs, path childAt 1):_*)
            }) ++ after.getOrElse(Empty)
          case None => Elem(p, l, as, s, marks(cs, path childAt 1):_*)
        }
      case z@_ => z ++ marks(z.child, path childAt 1)
    }) ++ mark(tl, path++)
    case Nil => NodeSeq.Empty
  }
  
  def marks(ns: NodeSeq, path: LocationPath): NodeSeq = ns.toList match {
    case hd :: tl => mark(hd, path) ++ marks(tl, path++)
    case Nil      => NodeSeq.Empty
  }
}
